home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / 80X86 / DOS32V33.ZIP / EXAMPLES / GUSFILL.ASM < prev    next >
Encoding:
Assembly Source File  |  1995-09-20  |  18.6 KB  |  589 lines

  1. ;**************************************************************************
  2. ;  GUSFILL.ASM
  3. ;
  4. ;  This example program does sends some stuff to/from the GUS via DMA.
  5. ;  The code here is explained in detail. It is a good example for someone
  6. ;  who would like to start coding for thier GUS. See IRQ handler for
  7. ;  details on handling interrupts from the GUS.
  8. ;
  9. ;
  10. ;   to compile;
  11. ;
  12. ;   tasm gusfill.asm      or     ml /c /Dmasm gusfill.asm
  13. ;   dlink gusfill.obj ..\lib\dma.obj ..\lib\gus.obj
  14. ;
  15. ;  note that this program requires the GUS.ASM and DMA.ASM library
  16. ;
  17. ;
  18. ; Written by Adam Seychell
  19. ;**************************************************************************
  20. .386
  21. .model  flat ,C
  22. .stack
  23.  
  24.  
  25. include  dma.inc
  26. include  gus.inc
  27.  
  28.  
  29. ;-------------------------------------------------------------------------
  30. ;              DISPLAY A STRING ON SCREEN WITH CARAGE RETURN
  31. ;
  32. ; Usage:       Writeln   <' string to display '>
  33. ;
  34. ;
  35. ;-------------------------------------------------------------------------
  36. writeln MACRO STRING_
  37. LOCAL TEXT3_S,skip_wrln
  38.         push eax
  39.         push edx
  40.         jmp skip_wrln
  41. TEXT3_S DB STRING_,13,10,36
  42. skip_wrln:
  43.         mov EDX,offset TEXT3_S
  44.         mov ah,9
  45.         Int 21h
  46.         pop edx
  47.         pop eax
  48. ENDM
  49.  
  50.  
  51. gf1_clock               equ 617400
  52.  
  53. .DATA
  54.  
  55. DMA_buffer_phys         dD ?
  56. DMA_buffer_addr         dD ?
  57. DMA_DRAM_address        dD ?
  58. GUS_MEMORY              dD ?
  59. DMA_Play_Chan           dB ?
  60. DMA_Samp_Chan           dB ?
  61. DMAPlay_TC              dB ?
  62. gf1_IRQ                 dB ?
  63. midi_IRQ                dB ?
  64.  
  65.  
  66. .CODE
  67.  
  68. The_Start:;**************** ENTRY POINT OF THE PROGRAM ************
  69.  
  70.  
  71. ;********* Allocate a 16KB DMA buffer  ***************
  72.         mov     ax,0EE41h                       ; call a DOS32 service
  73.         int     31h
  74.         jc      error_dma_buffer
  75.         mov     DMA_buffer_addr,edx             ; save the address
  76.         mov     DMA_buffer_phys,ebx
  77.  
  78.  
  79.  
  80.  
  81. ;********* Get the Default GUS settings from the "ULTRASND=" string *********
  82.         Call    GetUltraConfig                  ; See GUS.ASM
  83.         jc Error_EnvString
  84.  
  85.         mov     DMA_Play_Chan,CL                     ; save DMA channels
  86.         mov     DMA_Samp_Chan,CH
  87.         mov     gf1_IRQ,BL
  88.         mov     midi_IRQ,BH
  89.  
  90.  
  91. ;************  Fully reset the Ultraosund *************************
  92.  
  93.                                             ;Expects BL=gf1 IRQ
  94.                                             ;        BH=midi IRQ
  95.                                             ;        CL=dram DMA chan
  96.                                             ;        CL=adc DMA chan
  97.          call    Ultrasound_Reset           ;        DX=base port
  98.          jc     bad_reset
  99.  
  100.                                             ; returns EDI = gus memory size
  101.         mov     GUS_MEMORY,EDI
  102.  
  103.  
  104.         writeln  'Filling Ultrasound''s DRAM via DMA ( # = 16Kb ).'
  105.  
  106.  
  107.  
  108. ;************** Set the IRQ vector for the Ultrasound *****************
  109.         mov     edx,offset GUS_ISR
  110.         mov     cx,cs                           ; CX:EDX = selectro:offset
  111.         mov     bl,gf1_IRQ                      ; Convert IRQ to interrupt
  112.         cmp     bl,8                            ; number
  113.         jb Jpic1
  114.         add     bl,60h
  115. Jpic1:  add     bl,8
  116.         mov     ax,0205h                        ; Set interrupt vector
  117.         int     31h
  118.  
  119.  
  120.  
  121.  
  122. ; ****** program the 8237 DMA contoller  *************
  123.         mov     al,01011000b             ; DMA mode register
  124.         mov     ah,DMA_Play_Chan         ; Channel number ( 0..7 )
  125.         mov     ecx,04000h               ; Bytes to transfer
  126.         mov     ebx,DMA_buffer_phys      ; Physical base address
  127.         call    DMA_Setup                ; Do it ( see DMA.ASM )
  128.  
  129. ; Note: Mode register bit 4 is set for DMA auto initalizing mode.
  130. ; This means that the Address and Count registers don't have to be
  131. ; reprogramed after the DMA has finished transfering.
  132. ; i.e once the DMA has finished transfering it will pulse the TC
  133. ; line and also reload the Address and Count registers. The GUS card
  134. ; will invoke the hardware interrupt when it detects a signal on TC line.
  135.  
  136.         mov     DMA_DRAM_address,0              ; Reset fill counter
  137.  
  138.  
  139. FILL_GUS_LOOP:
  140.        ;********* Set the GUS's DMA DRAM staring address register *****
  141.        ;       note the wierdness when a 16bit dma channel is used
  142.        ;
  143.  
  144.         mov     dx,gf1_reg_select
  145.         mov     al,042h                       ; Set DMA Start Address
  146.         out     dx,al
  147.  
  148.         mov     eax,DMA_DRAM_address
  149.         test    DMA_Play_Chan,100b
  150.         jz _8bitDMA
  151.            ; ---- do 16 bit DMA address translation ( see the SDK ) -----
  152.           mov     edi,eax
  153.           shr     eax,1
  154.           and     eax,01ffffh     ; zero out bit 17..19
  155.           and     edi,0c0000h     ; get bits 18 and 19
  156.           or      eax,edi
  157. _8bitDMA:
  158.         shr     eax,4
  159.         mov     dx,gf1_data_low
  160.         out     dx,ax                   ; Set the damn register
  161.  
  162.  
  163.   ;********* Set the gf1 DMA Control Register  ****************
  164.  
  165.  
  166.         mov     al,041h                ;Set DRAM  DMA Control Register
  167.         mov     dx,gf1_reg_select
  168.         out     dx,al
  169.  
  170.         mov     ah,DMA_Play_Chan
  171.         and     ah,100b
  172.         mov     al,00100001b   ;Enable DMA, read, 650KB/s, 16bit data, 16/8bit DMA
  173.         or      al,ah
  174.         mov     dx,gf1_data_high
  175.         out     dx,al
  176.  
  177.  ; The DMA cycle will now start..........
  178.  
  179.  
  180.  
  181.  
  182.  
  183. ;********************** Wait around for the DMA to finish **************
  184.                 mov     ecx,50000h
  185. waitTC:         test    DMAPlay_TC,1            ; pole the flag
  186.                 loopz  waitTC
  187.                 jz   timoutERROR
  188.                 mov     DMAPlay_TC,0
  189.  
  190.  
  191.         mov     dl,'#'
  192.         mov     ah,2
  193.         int     21h
  194.  
  195.         add     DMA_DRAM_address,4000h
  196.         mov     eax,GUS_MEMORY
  197.         cmp     eax,DMA_DRAM_address
  198.         ja FILL_GUS_LOOP                ; loop until all memory filled.
  199.  
  200. ;****************** DRAM DMA transfering is completed ********************
  201. ;
  202. ; The DMA will no longer be transfering because the GUS's DRAM DMA control
  203. ; register has not been re-programed after the last DMA cycle. Once the
  204. ; TC has been reached the GUS automaically clears bit 0 of the control
  205. ; register to stop DMA from transfering. That is why the above loop
  206. ; must reload the DRAM DMA control register for each cycle.
  207. ;
  208.  
  209.  
  210. exit:
  211.  
  212. ; ****** program the 8237 DMA contollers  *************
  213.     ; Must turn of auto initalizing ????
  214.     ;   Sometimes my computer goes to about 1/8th of it's speed
  215.     ;   when if DMA auto initalizing bit is left on. Only a hardware reset
  216.     ;   will make it go back to normal. wierd yea?
  217.  
  218.         mov     al,00001000b             ; DMA mode register
  219.         mov     ah,DMA_Play_Chan         ; Channel number ( 0..7 )
  220.         call    DMA_Setup
  221.  
  222. ; ****** Terminate Program  *************
  223.         mov     ax,4C00h
  224.         int     21h
  225.  
  226.  
  227.  
  228.  
  229.  
  230. ;_________________________ ERROR MESSAGES ________________________________
  231. timoutERROR:;<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  232.         writeln  'ERROR:  got no IRQ form GUS'
  233.         jmp exit
  234. Error_EnvString:;<<<<<<<<<<<<<<<<<<<<<<<<
  235.         writeln  'Cannot find ''ULTRASND='' environment string or has invalid settings'
  236.         jmp exit
  237. bad_reset:;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  238.         writeln  'Could not detect and Ultrasound on this computer '
  239.         jmp exit
  240. error_dma_buffer:;<<<<<<<<<<<<<<<<<<<<<<<
  241.         writeln  'Not enough memory for 16Kb DMA buffer'
  242.         jmp exit
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249. comment ~
  250. *************************************************************************
  251.                      The Gravis Ultrasound IRQ handler
  252.  
  253.  The GUS's IRQ handler can be a tricky thing to do. As good as the SDK
  254.  ( Software Developers Kit) may be, I feel it doesn't not go into enough
  255.  detail on how to correctly handle IRQ's sent from the GUS. I will make
  256.  an attempt it here exaplaining.
  257.  
  258.  The following routine is a general IRQ handler and may be used for
  259.  haneling all types of IRQ's generated from the GUS. This program only
  260.  uses the DMA playback channel with all other IRQ sources turned off,
  261.  therefore this routine below only needs to handle IRQ's generated
  262.  from the TC ( Terminal Count ) send by the playback DMA channel.
  263.  
  264.  
  265.   Any of the following pices of the GUS's hardware can generate an IRQ.
  266.  
  267.    *   When a voice's current address is greater or equal to it's ending
  268.        address.
  269.    *   When a voice's current volume is greater or equal to it's
  270.         ending volume.
  271.    *   Timer 1 reached has a counting value of 0FFh.
  272.    *   Timer 2 reached has a counting value of 0FFh.
  273.    *   The playback DMA channel has finished transfering data.
  274.    *   The sampling DMA channel has finished transfering data.
  275.  
  276.  
  277.  Note that if a voice has LOOPING DISABLED then the voice's current
  278.  location will stop once it has reached it's ending location. This will
  279.  cause an IRQ ( assuming they are enabled for that voice) and will
  280.  continue to generate an IRQ each time the GF1 services that voice.
  281.  ( i.e IRQ's genrated at a rate equal to  617400Hz/number of active voices)
  282.  This is beacuse the current location is greater than or equal to the
  283.  the ending location. To stop this from happening the IRQ handler
  284.  must disable IRQ's for that voice if looping is set disabled. If looping is
  285.  enabled then we may leave the voices IRQ's enabled beacue the looping
  286.  effect returns the current location directly back to the starting location
  287.  once it hits the ending location. Therfore with looping enabled only
  288.  a single IRQ is generated at each time the voice loops.
  289.  This effect of repetitive IRQ generation for voices with looping disabled
  290.  also applies to volume ramping when the volume ramp looping is disabled.
  291.  Note carfully in the following routines on how the voice wave table and
  292.  volume ramping IRQs are handled so that repetitive IRQs are avoided.
  293.  
  294.  
  295.  
  296. *************************************************************************
  297. ~
  298. GUS_ISR  PROC
  299.  
  300.       ; setup usual IRQ stuff.
  301.  
  302.         push    ds                              ; Save all registers used
  303.         pushad
  304.         mov     ax,_TEXT                        ; Load DS with data selector
  305.         mov     ds,ax
  306.  
  307. LOOP_irq_handler:         ;<---- jumps here after particular IRQ is handled.
  308.  
  309. ;
  310. ; First determine sources of the IRQ's by looking at the irq status register.
  311. ; port 2x6h.
  312. ;
  313.         mov     dx,gf1_irq_status
  314.         in      al,dx
  315.         mov     irq_status,al
  316.  
  317.  
  318.       ; If all bits cleared then we are ready to exit the interrupt
  319.       ; routine.
  320.         test    al,11111111b
  321.         jz      exit_ISR
  322.  
  323.  
  324.         ;********************* MIDI Transmit ***********************
  325.         test    irq_status,00000001b
  326.         jz      done_MIDI_Tx
  327.  
  328.             ; midi transmit code can go here.....
  329.             ;
  330.             ;   call    midi_xmit_func
  331.  
  332.  
  333.         ;********************* MIDI Receive ***********************
  334. done_MIDI_Tx:
  335.         test    irq_status,00000010b
  336.         jz      done_MIDI_Rx
  337.          ;
  338.          ; Read MIDI data port. Note: this read also clears IRQ pending
  339.          ; so more midi receive IRQ's are avalible.
  340.  
  341.                mov   dx,midi_data
  342.                in    al,dx
  343.  
  344.             ; midi recieve code can go here.....
  345.             ;
  346.             ;   call    midi_recv_func
  347.  
  348.  
  349.  
  350. done_MIDI_Rx:
  351.         test    irq_status,00000100b
  352.         jz      done_Timer_1
  353.         ;********************* Timer 1 ***********************
  354.          ;
  355.          ; Pulse IRQ enable bit of timer controll register bit from 0 to 1.
  356.          ; If this is not done then no more IRQ's will be made from timer 1.
  357.          ;
  358.                mov   dx,gf1_reg_select
  359.                mov   al,45h
  360.                out   dx,al
  361.                mov   dx,gf1_data_high
  362.                in    al,dx
  363.                and   al,NOT 0100b               ; clear timer 1 IRQ enable
  364.                out   dx,al
  365.                or    al, 0100b                  ; set timer 1 IRQ enable
  366.                out   dx,al
  367.  
  368.             ;
  369.             ;  timer 1 code can go here........
  370.             ;
  371.             ;   call    timer1_func
  372.  
  373.  
  374. done_Timer_1:
  375.         test    irq_status,00001000b
  376.         jz      done_Timer_2
  377.         ;********************* Timer 2 ***********************
  378.          ;
  379.          ; Pulse IRQ enable bit of timer controll register bit from 0 to 1.
  380.          ; If this is not done then no more IRQ's will be made from timer 2.
  381.          ;
  382.                mov   dx,gf1_reg_select
  383.                mov   al,45h
  384.                out   dx,al
  385.                mov   dx,gf1_data_high
  386.                in    al,dx
  387.                and   al,NOT 1000b               ; clear timer 2 IRQ enable
  388.                out   dx,al
  389.                or    al, 1000b                  ; set timer 2 IRQ enable
  390.                out   dx,al
  391.  
  392.             ;
  393.             ;  timer 2 code can go here........
  394.             ;
  395.             ;   call    timer2_func
  396.  
  397.  
  398.  
  399.  
  400.         ;************ Voice Wave Table and/or Volume Ramp **********************
  401. done_Timer_2:
  402.         test    irq_status,01000000b or 00100000b
  403.         jz      done_WT_VR
  404.  
  405.         Call    Service_Voice_Interrupt         ; see routine below
  406.  
  407.  
  408.  
  409.  
  410.         ;********************* DMA TC ( sample and/or playback ) ***************
  411. done_WT_VR:
  412.         test    irq_status,10000000b
  413.         jz      LOOP_irq_handler
  414.  
  415.      ;
  416.      ; Read the DRAM DMA control register. Reading this register also
  417.      ; clears the IRQ pending bit which allows another DRAM IRQ to
  418.      ; occurr. If we do not read this then DMA DRAM will not generate
  419.      ; anymore IRQs.
  420.      ;
  421.         mov     dx,gf1_reg_select
  422.         mov     al,041h             ; DRAM  DMA Control Register
  423.         out     dx,al
  424.         mov     dx,gf1_data_high    ; read
  425.         in      al,dx
  426.         test    al,01000000b        ; was it a DRAM DMA IRQ
  427.         jz      check_sample_TC     ; if not then do SAMPLE DMA IRQ
  428.  
  429.              ;
  430.              ;  code can go here for playback DMA terminal count.......
  431.              ;
  432.                     or      DMAPlay_TC,1
  433.              ;  call    dram_dma_tc_func
  434.                 jmp  LOOP_irq_handler
  435.  
  436.  
  437.  
  438. check_sample_TC:
  439.      ;
  440.      ; Read the SAMPLE DMA control register. Reading this register also
  441.      ; clears the IRQ pending bit which allows another IRQ.
  442.      ;
  443.         mov     dx,gf1_reg_select
  444.         mov     al,049h
  445.         out     dx,al
  446.         mov     dx,gf1_data_high
  447.         in      al,dx
  448.  
  449.              ;
  450.              ;  code can go here for sampling DMA terminal count.......
  451.              ;
  452.                  ; ..... ..... ..
  453.  
  454.              ;  call    sample_dma_tc_func
  455.                 jmp  LOOP_irq_handler
  456.  
  457.  
  458. ; Exit the interrupt routine.
  459. exit_ISR:
  460.         mov     al,020h                 ; Send EOI command to both PICs (8259)
  461.         out     20h,al
  462.         out     0A0h,al
  463.         popad
  464.         pop     ds
  465.         iretd
  466.  
  467. irq_status DB  0
  468.  
  469. GUS_ISR ENDP
  470. ;******************** End of Gravis ultrasound IRQ handler ******************
  471.  
  472.  
  473.  
  474.  
  475.  
  476. comment ~
  477. ******************************************************
  478.             Voice Interrupt Handler
  479.  
  480.  This routine handles IRQs generated from any of the voices.
  481.  In other words when voice has reched it's ending location or it's
  482.  ending volume.
  483.  It's possible that multiple voices could interrupt at the same time
  484.  or interrupt while still services other voices interrupts. The handler
  485.  must keep on reading the IRQ source register( reg number 8Fh) until
  486.  all voices are cleared of interrupt requests ( i.e until bits 7 & 6
  487.  are both set).
  488.  
  489.   ----- IRQ Source Register format ------
  490.   bit 0..4 = interrupting voice
  491.   bit 5 = 1 ( ingnore this )
  492.   bit 6 = volume ramp irq pending
  493.   bit 7 = volume ramp irq pending
  494.  
  495. *******************************************************~
  496. Service_Voice_Interrupt PROC
  497.  
  498. Local   Wave_Ignore,Volume_Ignore :dword
  499.  
  500.         mov     Volume_Ignore,0
  501.         mov     Wave_Ignore,0
  502. SERVICE_LOOP:
  503.         mov     dx,gf1_reg_select       ; Read the IRQ source register
  504.         mov     al,8Fh
  505.         out     dx,al
  506.         add     dl,2
  507.         in      al,dx
  508.         mov     ch,al
  509.         and     ch,11000000b
  510.         cmp     ch,11000000b            ; check if any IRQs are left
  511.         je FIFO_empty                   ; if not then exit routine
  512.         and     al,011111b
  513.         mov     cl,al                   ; Save voice number in CL
  514.         mov     ebx,1
  515.         shl     ebx,cl
  516.  
  517.      ;
  518.      ; CL  = voice we need to service.
  519.      ; CH  = bits 6 & 7 of irq source register
  520.      ; EBX = 1 SHL voice number .
  521.  
  522.         push    ECX                             ; save these registers.
  523.         push    EBX
  524.  
  525.      ; Did Wave Table cause IRQ ?.
  526.      ;
  527.         test    CH,10000000b                    ; look at bit 7 of IRQ source
  528.         jnz     was_not_a_WT
  529.  
  530.      ; see if voice has already been service. If so then ignore it.
  531.      ;
  532.         test    Wave_Ignore,ebx
  533.         jnz     was_not_a_WT
  534.         or      Wave_Ignore,ebx         ; mark voice to ingnore in future.
  535.  
  536.      ; your code goes here to handle the particular voices wave table
  537.      ; interrupt. NOTE: if volume looping is disabled or rollover is enabled
  538.      ; then you must disable the voice's IRQs ( by clearing bit 5 of Voice
  539.      ; Control register ) or you'll be flooded with IRQ's.
  540.  
  541.        ; .......wave table irq code.......
  542.  
  543.  
  544.  
  545.  
  546.  
  547. was_not_a_WT:
  548.      ; Did  volume ramp cause IRQ ?.
  549.      ;
  550.         pop     ECX                             ; restore these registers
  551.         pop     EBX
  552.         test    CH,01000000b                    ; look at bit 6 of IRQ source
  553.         jnz     was_not_a_Vol
  554.  
  555.      ; see if voice has already been service. If so then ignore it.
  556.      ;
  557.         test    Volume_Ignore,ebx
  558.         jnz     was_not_a_Vol
  559.         or      Volume_Ignore,ebx       ; mark voice to ingnore in future
  560.  
  561.      ; your code goes here to handle the particular voices volume ramp
  562.      ; interrupt. NOTE: if volume looping is disabled then you must
  563.      ; disable the voice's volume ramp IRQs ( by clearing bit 5 of Volume
  564.      ; Ramp Control register ) or you'll be bombarded with IRQ's.
  565.  
  566.        ; .......volume ramp irq code.......
  567.  
  568.  
  569.  
  570.  
  571.  
  572. was_not_a_Vol:
  573.         jmp     SERVICE_LOOP             ; contiue servicing interrupts.
  574.                                          ; until there all gone.
  575.  
  576.  
  577. FIFO_empty:    ;<---- jumps here when bits 6 & 7 of the IRQ source
  578.                ;      register are both set, i.e no irq's waiting.
  579.  
  580.         Ret                             ; return to main IRQ handler
  581.  
  582. Service_Voice_Interrupt ENDP
  583. ;********************* End of voice interrupt handler **********************
  584.  
  585.  
  586.  
  587. END The_Start
  588.